
#include "..\d3d.h"
#include "..\interface_types.h"
#include "d3d_screenshader.h"
#include "d3d_depthmapshader.h"
#include "d3d_lightshader.h"
#include "d3d_particleshader.h"
#include "..\d3d_texture.h"
#include "..\d3d_mesh.h"
#include "..\..\common\string.h"
#include "..\..\common\def.h"
#include "..\..\common\util.h"
#include "..\..\engine\engine.h"
#include "..\..\engine\memorymanager.h"
#include "..\..\engine\error.h"
#include "..\..\math\math.h"

string D3DScreenShader::Identifier()
{
	return "D3DScreenShader"; 
}

string D3DScreenShader::GetType() const
{
	return string("D3DScreenShader"); 
}

/**************************************
 *
 **************************************/
D3DScreenShader::D3DScreenShader(CD3D9Device* const pDevice) : D3DShader(pDevice)
{	
	m_pHBlur = NULL;
	m_pVBlur = NULL;

	m_pHBlurTechnique = NULL;
	m_pVBlurTechnique = NULL;
	m_pCompositionTechnique = NULL;

	m_pInstanceVB = NULL; 
	m_lastInstanceCount = 0; 

	m_pEffect = NULL; 
	m_Identity = "D3DScreenShader"; 
}

/**************************************
 *
 **************************************/
void D3DScreenShader::AddRenderQue(D3DRenderable* pMesh, const Matrix4f& transform)
{
	EE_LOGERROR("Warning: meaningless call.");
}

/**************************************
 *
 **************************************/
void D3DScreenShader::AddRenderQue(const D3DMesh::RenderInstance& instance)
{
	EE_LOGERROR("Warning: meaningless call.");
}

/**************************************
 * Implementations to aquire specfiy custom 
 * effect parameters
 **************************************/
HRESULT D3DScreenShader::InitalizeParameters(LPD3DXEFFECT pEffect)
{
	HRESULT hr;
	do {

		if(ISNULL(pEffect)) {
			EE_LOGERROR("Invalid parameter.");
			hr = E_INVALIDARG;
			break;
		}

		m_pCompositionTechnique = pEffect->GetTechniqueByName( "t_ComputeComposition" ); 
		m_pVBlurTechnique = pEffect->GetTechniqueByName( "t_ComputeVBlur" ); 
		m_pHBlurTechnique = pEffect->GetTechniqueByName( "t_ComputeHBlur" ); 
	
		if(ISNULL(m_pCompositionTechnique) || 
			ISNULL(m_pVBlurTechnique) || ISNULL(m_pHBlurTechnique)) {
			EE_LOGERROR("Unknown semantic.");
			hr = E_UNEXPECTED;
			break;
		}

		return S_OK;
	
	}while(false);
	
	m_pCompositionTechnique = NULL;
	m_pVBlurTechnique = NULL;
	m_pHBlurTechnique = NULL;
	return hr;
}

/**************************************
 *
 **************************************/
HRESULT D3DScreenShader::Create(const string& filename)
{
	HRESULT hr;
	RenderTarget* pHBlur = NULL;
	RenderTarget* pVBlur = NULL;
	LPD3DXEFFECT pEffect = NULL;
	LPD3DXBUFFER pErrors = NULL; 
	DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE; 
	#ifdef _DEBUG
			dwShaderFlags |= D3DXSHADER_DEBUG; 
	#endif

	do {

		if(ISNULL(GetDevice())) {
			EE_LOGERROR("Shader has no graphics device."); 
			hr = E_UNEXPECTED;
			break;
		}

		if(!filename.IsValid()) {
			EE_LOGERROR("Bad shader filename."); 
			hr = E_INVALIDARG;
			break;
		}

		string filepath = CEngine::GetInstance()->FindFilepath(filename); 
		if(!filepath.IsValid()) {
			EE_LOGERROR("Failed to locate file."); 
			hr = E_FAIL;
			break;
		}

		if(D3DXCreateEffectFromFile(GetDevice()->m_pD3DDevice,filepath.c_str(),
			NULL,NULL,dwShaderFlags,GetEffectPool(),&pEffect,&pErrors) != D3D_OK) {
			EE_LOGERROR((char*)pErrors->GetBufferPointer()); 
			EE_LOGERROR("Failed to load shader."); 
			hr = E_FAIL;
			break;
		}

		if(FAILED(InitalizeParameters(pEffect))){
			EE_LOGERROR("Failed to initalize parameters."); 
			hr = E_FAIL;
			break;
		}

		pHBlur = EE_NEW RenderTarget(GetDevice());
		pVBlur = EE_NEW RenderTarget(GetDevice());

		if(ISNULL(pHBlur) || ISNULL(pVBlur)) {
			hr = E_OUTOFMEMORY;
			break;
		}

		const DeviceSettings deviceSettings = GetDevice()->GetDeviceSettings();
		if(FAILED(GetDevice()->createRenderTarget(pHBlur, deviceSettings.screenWidth, deviceSettings.screenHeight, D3DFMT_A8B8G8R8, false)) ||
			FAILED(GetDevice()->createRenderTarget(pHBlur, deviceSettings.screenWidth, deviceSettings.screenHeight, D3DFMT_A8B8G8R8, false))) {
			EE_LOGERROR("Failed to create render targets."); 
			hr = E_FAIL;
			break;
		}

		if(ISNULL(m_pEffect)) {

			if(FAILED(Release())) {
				EE_LOGERROR("Failed to release shader resources."); 
				hr = E_FAIL;
				break;
			}
		}
	
		m_pVertexDeclaration = NULL;
		m_pEffect = pEffect;
		m_Identity = filename; 
		m_pHBlur = pHBlur;
		m_pVBlur = pVBlur;
		return S_OK; 

	}while(false);

	if(pHBlur) {
		pHBlur->Release();
		EE_SAFEDELETE(pHBlur);
	}

	if(pVBlur) {
		pVBlur->Release();
		EE_SAFEDELETE(pVBlur);
	}

	if(pEffect) {
		pEffect->Release();
		pEffect = NULL;
	}
	Release();
}

/**************************************
 *
 **************************************/
void D3DScreenShader::FlushRenderList(void) {

	EE_LOGERROR("Warning: meaningless call.");
}

/**************************************
 *
 **************************************/
void D3DScreenShader::Execute(const int flags) {

	EE_LOGERROR("Warning: meaningless call.");
}

/**************************************
 *
 **************************************/
void D3DScreenShader::Execute(LPDIRECT3DSURFACE9 pFinalSurface, LPDIRECT3DTEXTURE9 pScreenBuffer)
{
	RenderTarget* pFinalComposition = m_pHBlur;
	uint passes = 0; 
	LPDIRECT3DDEVICE9 pDevice = GetDevice()->GetDevice();

	pDevice->SetRenderTarget(0, m_pHBlur->m_pSurface);
	pDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
	pDevice->SetRenderTarget(1, NULL);
	pDevice->SetRenderTarget(2, NULL);
	m_pEffect->SetTechnique(m_pHBlurTechnique);

	pDevice->BeginScene();
	m_pEffect->Begin(&passes,0); 
	for(uint i = 0;  i < passes; i++)
	{
		m_pEffect->BeginPass(i); 
		GetDevice()->RenderScreenGeometry(); 
		m_pEffect->EndPass(); 
	}
	m_pEffect->End(); 
	pDevice->EndScene();

	pDevice->SetRenderTarget(0, m_pVBlur->m_pSurface);
	GetDevice()->SetTexture(2, m_pHBlur->m_pTargetTexture);
	m_pEffect->SetTechnique(m_pVBlurTechnique);

	pDevice->BeginScene();
	m_pEffect->Begin(&passes,0); 
	for(uint i = 0;  i < passes; i++)
	{
		m_pEffect->BeginPass(i); 
		GetDevice()->RenderScreenGeometry(); 
		m_pEffect->EndPass(); 
	}
	m_pEffect->End(); 
	pDevice->EndScene();

	GetDevice()->GetDevice()->SetRenderTarget(0, pFinalSurface);
	GetDevice()->SetTexture(0, pScreenBuffer);
	GetDevice()->SetTexture(2, m_pVBlur->m_pTargetTexture);
	m_pEffect->SetTechnique(m_pCompositionTechnique);

	pDevice->BeginScene();
	m_pEffect->Begin(&passes,0); 
	for(uint i = 0;  i < passes; i++)
	{
		m_pEffect->BeginPass(i); 
		GetDevice()->RenderScreenGeometry(); 
		GetDevice()->RenderScreenItems();
		m_pEffect->EndPass(); 
	}
	m_pEffect->End(); 
	

	pDevice->EndScene();
}

/**************************************
 *
 **************************************/
void D3DScreenShader::PreExecute()
{
	EE_LOGERROR("Warning: meaningless call.");
}

/**************************************
 *
 **************************************/
void D3DScreenShader::PostExecute()
{	
	EE_LOGERROR("Warning: meaningless call.");
}


/**************************************
 *Attempts to release resources asocciated
 *with this shader
 **************************************/
HRESULT D3DScreenShader::Release()
{
	m_IsValid = false; 
	GetDevice()->DeregisterResource(this); 

	if(m_pEffect)
	{
		m_pEffect->Release(); 
		m_pEffect = NULL; 
	}

	Identity().empty(); 

	if(m_pHBlur) {
		m_pHBlur->Release();
		EE_SAFEDELETE(m_pHBlur);
	}
	
	if(m_pVBlur) {
		m_pVBlur->Release();
		EE_SAFEDELETE(m_pVBlur);
	}

	m_pHBlurTechnique = NULL;
	m_pVBlurTechnique = NULL;
	m_pCompositionTechnique = NULL;

	return S_OK; 
}